package com.hyt.it.ogt.kq.service.gov.aspect;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.hyt.it.ogt.kq.common.gov.constant.examsys.ActionEnum;
import com.hyt.it.ogt.kq.service.gov.model.dto.ExamSystemRequestDTO;
import com.hyt.it.ogt.kq.service.gov.service.ITaskService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * 考试系统切面
 * </p>
 *
 * @author huangyh
 * @since 2021-09-09
 */
@Aspect
@Slf4j
@Component
public class ExamSystemAspect {

    @Resource
    private ITaskService iTaskService;

    /**
     * 切点
     */
    @Pointcut("@annotation(com.hyt.it.ogt.kq.common.gov.annotation.ExamSys)")
    public void examSystemPointCut() {

    }

    /**
     * 执行前
     * @param joinPoint 连接点
     */
    @Before(value = "examSystemPointCut()")
    public void doBefore(JoinPoint joinPoint) {
        //获取考试系统请求信息
        ExamSystemRequestDTO info = getRequestInfo(joinPoint);
        //记录日志
        log.info("考试系统请求参数 ({}) : {}", info.getTaskCode(),
                JSON.toJSONString(info.getParameterMap(),
                        SerializerFeature.PrettyFormat,
                        SerializerFeature.WriteMapNullValue));
    }

    /**
     * 环绕
     * @param joinPoint 连接点
     * @return 结果
     * @throws Throwable 异常
     */
    @Around(value = "examSystemPointCut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        ExamSystemRequestDTO info = getRequestInfo(joinPoint);
        //校验考试任务是否发布
        if (iTaskService.getPublishByCode(info.getTaskCode())) {
            //考试任务已发布
            return joinPoint.proceed();
        } else {
            //考试任务未发布，统一返回null
            //记录日志
            log.info("考试任务 ({}) 未发布", info.getTaskCode());
            return null;
        }
    }

    /**
     * 返回结果后
     * @param result 返回结果
     */
    @AfterReturning(returning = "result", value = "examSystemPointCut()")
    public void doAfterReturning(JoinPoint joinPoint, String result) {
        //获取考试系统请求信息
        ExamSystemRequestDTO info = getRequestInfo(joinPoint);
        //记录日志
        log.info("{} ({}) 考务返回结果 : {}",
                info.getParameterMap().get(ActionEnum.ACTION.getName()),
                info.getTaskCode(), result);
    }

    /**
     * 获取考试系统请求信息
     * @param joinPoint 连接点
     * @return 考试系统请求信息
     */
    private ExamSystemRequestDTO getRequestInfo(JoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        //获取请求参数名数组
        String[] parameterNames =  methodSignature.getParameterNames();
        //获取请求参数值数组
        Object[] args = joinPoint.getArgs();
        //获取请求参数Map
        int requestIndex = ArrayUtils.indexOf(parameterNames,"request");
        HttpServletRequest request = (HttpServletRequest) args[requestIndex];
        Map<String, String> parameterMap = new HashMap<>();
        Enumeration<String> paramNames = request.getParameterNames();
        while (paramNames.hasMoreElements()) {
            String paramName = paramNames.nextElement();
            String[] paramValues = request.getParameterValues(paramName);
            if (paramValues.length == 1) {
                parameterMap.put(paramName, paramValues[0]);
            }
        }
        //获取考试任务编号
        int taskCodeIndex = ArrayUtils.indexOf(parameterNames,"taskCode");
        String taskCode = args[taskCodeIndex].toString();
        ExamSystemRequestDTO info = new ExamSystemRequestDTO();
        info.setTaskCode(taskCode).setParameterMap(parameterMap);
        return info;
    }

}
